import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class SearchSerlvet
 */

class resultObject {
	private String[] results;
	private String totalResult = "";
	private String fileToOpen = "";
	private final String resultsDelimiter = "#repository_disjoint_point#";
	
	public void setTotalResult(String result) {
		this.totalResult = result;
	}
	
	public String getTotalResult() {
		return this.totalResult;
	}
	
	public void setResults(String[] input) {
		this.results = input;
	}
	
	public String[] getResults() {
		return this.results;
	}
	
	public void setFileToOpen(String file2open) {
		this.fileToOpen = file2open;
	}
	
	public String getFileToOpen() {
		return this.fileToOpen;
	}
	
	public String getResultsDelimiter() {
		return this.resultsDelimiter;
	}
	
	public void printResultObject() {
		System.out.println("####### Result Object #######");
		System.out.println("Results: {");
		for (int i = 0; i < this.results.length; i++)
			System.out.println("\t"	+ this.results[i]);
		System.out.println("}");
		System.out.println("totalResult: " + this.totalResult);
		System.out.println("fileToOpen: " + this.fileToOpen);
		System.out.println();
	}
}

class searchObject {
	private int pageNumber = 1;
	private int itemPerPage = 20;
	//private Hashtable<String, String> queryString = new Hashtable<String, String>();
	private LinkedList<String[]> filter = new LinkedList<String[]>();		// filter, value
	private String sort  = "";
	private String type  = "";
	private String templateName = "";
	private String template = "";
	private Hashtable<String, String> relation = new Hashtable<String, String>();
	private LinkedList<String[]> filters = new LinkedList<String[]>();
	private LinkedList<String[]> searchLists = new LinkedList<String[]>();
	private LinkedList<String[]> sorts = new LinkedList<String[]>();
	private LinkedList<String[]> relations = new LinkedList<String[]>();
	private LinkedList<String[]> resourceTypes = new LinkedList<String[]>(); 

	private void printLinkedList(LinkedList<String[]> list, String name) {
		System.out.println(name + ": {");
		Iterator<String[]> pointer = list.iterator();
		while (pointer.hasNext()) {
			String item[] = pointer.next();
			System.out.print("\t");
			for (int i = 0; i < item.length; i++)
				System.out.print(item[i] + "\t");
			System.out.println();
		}
		System.out.println("}");
	}
	
	public void printSearchObject() {
		System.out.println("####### Search Object #######");
		System.out.println(this.templateName + ": " + this.template);
		System.out.println("pageNumber: " + this.pageNumber);
		System.out.println("itemPerPage: " + this.itemPerPage);
		this.printLinkedList(this.filter, "filter");
		System.out.println("sort: " + this.getSort());
		System.out.println("order: " + this.getOrder());
		System.out.println("type: " + this.type);
		Iterator<String> iter = this.relation.keySet().iterator();
		System.out.println("relation: {");
		while (iter.hasNext()) {
			String key = iter.next();
			System.out.println("\t" + key + ", " + this.relation.get(key));
		}
		System.out.println("}");
		this.printLinkedList(this.filters, "filters");
		this.printLinkedList(this.searchLists, "searchLists");
		this.printLinkedList(this.sorts, "sorts");
		this.printLinkedList(this.relations, "relations");
		this.printLinkedList(this.resourceTypes, "resourceTypes");
		System.out.println();
	}
	
	public String getTemplateName() {
		return this.templateName;
	}
	
	public String getTemplate() {
		return this.template;
	}
	
	public int getPageNumber() {
		return this.pageNumber;
	}
	
	public int getItemPerPage() {
		return this.itemPerPage;
	}
	
	public void setTemplate(String template) {
		this.template = template;
	}
	
	public void setTemplateName(String name) {
		this.templateName = name;
	}
	
	public void setItemPerPage(int itemsNumber) {
		this.itemPerPage = itemsNumber;
	}
	
	public void setPageNumber(int sp) {
		this.pageNumber = sp;
	}
	
	public LinkedList<String[]> getFilter() {
		return this.filter;
	}
	
	public String getOrder() {
		Iterator<String[]> iter = this.sorts.iterator();
		while (iter.hasNext()) {
			String item[] = iter.next();
			if (this.sort.length() == 0)
				return "";
			if (this.sort.equals(item[1]))
				return item[2];
		}
		return "";
	}
	
	public String getSort() {
		return this.sort;
	}	
	
	public LinkedList<String[]> getFilters() {
		return this.filters;
	}
	
	public LinkedList<String[]> getSearchLists() {
		return this.searchLists;
	}
	
	public LinkedList<String[]> getSorts() {
		return this.sorts;
	}
	
	public Hashtable<String, String> getRelation() {
		return this.relation;
	}
	
	public String getRelation(String index) {
		return ( this.relation.get(index) == null ) ? "" : this.relation.get(index);
	}
	
	public LinkedList<String[]> getRelations() {
		return this.relations;
	}
	
	public void addFilter(String filter, String value) {
		String input[] = {filter, value};
		this.filter.add(input);
	}

	public void setSort(String sort) {
		this.sort = sort;
	}
	
	public void addSorts(String label, String sort, String order) {
		String input[] = {label, sort, order};
		this.sorts.add(input);
	}
	
	public void addFilters(String label, String filter) {
		String input[] = {label, filter};
		this.filters.add(input);
	}
	
	public void addSearchLists(String label, String filter) {
		String input[] = {label, filter};
		this.searchLists.add(input);
	}
	
	public void setRelation(String index, String value) {
		this.relation.put(index, value);
	}
	
	public void addRelations(String label, String relation) {
		String input[] = {label, relation};
		this.relations.add(input);
	}
	
	public void addResourceTypes(String label, String type) {
		String input[] = {label, type};
		this.resourceTypes.add(input);
	}
	
	public void setResourceType(String type) {
		this.type = type;
	}
	
	public LinkedList<String[]> getResourceTypes() {
		return this.resourceTypes;
	}
	
	public String getResourceType() {
		return this.type;
	}
	
	public String getFilterViaLabel(String label) {
		Iterator<String[]> iter = this.filters.iterator();
		while (iter.hasNext()) {
			String[] input = iter.next();
			if (input[0].equalsIgnoreCase(label))
				return input[1];
		}
		return null;
	}
}

public class SearchServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;	
	private static final String DWLeftBracket = "document.write(\"";
	private static final String DWRightBracket = "\");";
	private static final String Command = "command";
	private static final String IFrameURL = "url";
	private static final String Template = "template";
	private static final String TempDirectory = "temp/";
	private static final String XSLDirectory   = "xsl/";
	private static final String ConfDirectory 	= "conf/";
	//private static final String ConfSuffix		= ".conf";
	private static final String ConfFile	  	= "conf.xml";
	private static final String DBMappingFile 	= "mapping/mapping-db.conf";
	private static final String SSMappingFile 	= "mapping/mapping-searchscript.conf";
	private static final String TempFileSuffix  = "seh";
	private static final String FS = System.getProperty("file.separator");
	//private static final String JavascriptDir   = "js/";
	//private static final String JSIFrame		= "repository_searchscript.js";
	private static final String TokenHeader = "";
	private static final String TokenEnd = "#repository_searchscript_header#";
	private static final String NoResultReturns = "Your search has not returned any results. <br/>Please check that all the search terms have been spelt correctly. <br/>You may also wish to broaden your search by selecting more general search criteria or keywords.";
	private static final String SelectAllLabel = "Select all";
	private static final String UnSelectAllLabel = "Clear all";
	
	private String SearchScriptDiv = "repository_searchscript_div";
	private String PageTop = "repository_searchscript_top";
	private String Conjunction = "repository_conjunction";
	private String Fields = "repository_field";
	private String Query = "repository_query";
	private String ResourceType = "repository_resourcetype";
	private String Legend = "Search Repository";
	//private String CheckBox = "repository_checkbox";
	private String SearchFieldDiv = "repository_searchfield_div";
	private String repositorySortDiv = "repository_sort_div";
	private String DataTableDiv = "repository_datatable_div";
	private String repositoryTableDiv = "repository_table_div";
	private String repositoryPageDiv = "repository_pagenumber_div";
	private String LoadingImageDiv = "repository_loadingimage_div";
	private String SaveCitationDiv = "repository_save_citation_div";
	private String CitationDropDown = "repository_citationbyselect";
	private String SortDropDown = "repository_sortbyselect";
	private String CitationCheckBox = "repository_citationchk";
	private String repositoryInnerIframe	= "repository_inneriframe";
	private String repositoryPid			= "repository_pid";
	private String Address				= "repository_address";
	private String repositoryTemplate		= "repository_template";
	
	private String Delimiter	   = "";
	private String CitationRequest = "";
	private String RequestURL = "";
	private String RepositoryURL = "";
	private String RepositoryURLTarget = "";
	private String MetaData = "";
	private String Fedora	= "";
	private String ServletContext = "";
	private String SearchFieldSet = "";
	private String Stylesheet = "";
	private String RepositoryName = "";
	
	private void clean() {
		this.MetaData = "";
		this.Fedora = "";
		this.ServletContext = "";
		this.SearchFieldSet = "";
	}
	
	private void readFromConfig() throws MP2Exception {		
		String rootTag 			= "module";
		String identifier 		= "name";
		String pointer	  		= "searchscript";
		Configuration cf = new Configuration(ServletContext + FS + ConfDirectory + ConfFile, 
											 rootTag,
											 identifier,
											 pointer);		
		String stops[] = {"linktorepository",
						  "linktorepositorytarget",
						  "metadata",
						  "fedora",
						  "stylesheet",
						  "searchfieldset", 
						  "requesturl",
						  "citationurl",
						  "xsldelimiter",
						  "repositoryname"};
		String results[];
		try {
			results = cf.readFromConfig(stops);
		} catch (Exception e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.ReadingConfFileErr);
			e.printStackTrace();
			throw mp2;
		}
		
		RepositoryURL 		= results[0];
		RepositoryURLTarget = results[1];
		MetaData    		= results[2];
		Fedora	    		= results[3];
		Stylesheet  		= results[4];
		SearchFieldSet 		= results[5];
		RequestURL			= results[6];
		CitationRequest		= results[7];
		Delimiter			= results[8];
		RepositoryName		= results[9];
		Legend				= "Search "+RepositoryName;	
	}
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) {
		this.requestHandler(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) {
		this.requestHandler(request, response);
	}
	
	private String addQuotation(String line) {
		String regex = "\"";
		String replacement = "\\" + "\""; 
		return line.replace(regex, replacement);
	}
	/*
	protected boolean isNewSession(HttpServletRequest req) {
		HttpSession session = req.getSession();
		return session.isNew();
	}
	*/
	
	private String produceButton(String type, String value, String onclick, String style, String name, String id) {
		String input = "<input" +
					((type.length() > 0)?	" type='" + type + "'" : "") +
					((value.length() > 0)?	" value='" + value + "'" : "") +
					((onclick.length() > 0)?	" onclick='javascript:" + onclick + "'" : "") +
					((style.length() > 0)?	" class='" + style + "'" : "") +
					((name.length() > 0)?	" name='" + name + "'" : "") +
					((id.length() > 0)?	" id='" + id + "'" : "") +
					" />"; 
		
		return input;
	}
	
	private String printSearchFrame(searchObject object, String iframe) throws MP2Exception {
		String fieldset =   "<body onload='resize()'>" +
							"<div id='" +SearchScriptDiv+ "' name='"+ SearchScriptDiv +"' class='" + SearchScriptDiv + "'>" + 
							"<div id='" + SearchFieldDiv + "' class='" + SearchFieldDiv +  " '>" +
							"<fieldset>" +
		 					"<legend>" + Legend + "</legend>" + 
		 					"<table><tbody>";
		Iterator<String[]> iter = object.getSearchLists().iterator();
		int index = 0;
		
		fieldset += "<tr>" + 
					"<td/>" +
					"<td/>" +
					"<td>" +
					this.produceButton("reset", "Reset", "repository_reset()", "button", "", "") +
					"</td>" +
					"</tr>";
		
		while (iter.hasNext()) {
			fieldset += "<tr>";
			String[] filters = iter.next();
			if (index > 0) {
				fieldset += "<td>" +
							"<select name=\"" + Conjunction + "\" id=\"" + Conjunction + "_" + index + "\">"; 
				Iterator<String[]> it = object.getRelations().iterator();
				while (it.hasNext()) {
					String[] conjunction = it.next();
					fieldset += "<option value=\"" + conjunction[1] + "\">" + conjunction[0] + "</option>";
				}
				fieldset += "</select>" + "</td>";
			} else {
				fieldset += "<td/>";
			}
			
			fieldset += "<td>" +
						"<select name=\"" + Fields + "\" id=\"" + Fields + "_" + index + "\">";
						
			Iterator<String[]> it = object.getFilters().iterator();			
			while (it.hasNext()) {
				String[] filterLabels = it.next();
				if (filters[1] == filterLabels[1]) 
					fieldset += "<option value=\"" + filterLabels[1] + "\" selected>" + filterLabels[0] + "</option>";
				else 
					fieldset += "<option value=\"" + filterLabels[1] + "\">" + filterLabels[0] + "</option>";
			}
			fieldset += "</select></td>" +
						"<td>" + "<input type=\"text\" value=\"\" id=\"" + Query + "_" + index +"\" name=\"" + Query +"\"/></td>";
			fieldset += "</tr>";
			index++;
		}		
		
		
		// buttons and all resources types
		fieldset += "<tr>" + 
					"<td/>" +
					"<td>";
		
		fieldset += "<select name=\"" + ResourceType + "\" id=\"" + ResourceType + "\">";
		
		iter = object.getResourceTypes().iterator();
		while (iter.hasNext()) {
			String[] types = iter.next();
			fieldset += "<option value=\"" + types[1] + "\">" + types[0] + "</option>";
		}
		fieldset +=  "</select></td>";
		
		fieldset +=	"<td>" +
					this.produceButton("button", "SEARCH", "repository_search()", "button", "", "") +
					"</td>" +
					"</tr>";
		fieldset += "</tbody></table>";
		fieldset += "</fieldset>";
		fieldset += "</div>";
		fieldset += "<a name='"+ PageTop +"'></a>";
		fieldset += "<br/>";
		fieldset += "<input id='"+ repositoryTemplate +"' type='hidden' name='" + repositoryTemplate + "' value='" + object.getTemplate() + "' />";
		fieldset += "<div id='"+ LoadingImageDiv +"' align='center' style='display:none;visibility:hidden;'><b>Loading Data: </b>&nbsp;&nbsp;<img src='./images/ajax-loader.gif'></div>";
		fieldset += "<div id='"+ DataTableDiv +"' style='display:none;visibility:hidden;'></div>";
		fieldset += "<div style='display:none;visibility:hidden;'><iframe src='" +iframe+ "' id='"+repositoryInnerIframe+"'></iframe></div>";
		fieldset += "</div>";
		fieldset += "</body>";
		String cssStyleSheet = "<link type='text/css' href='./css/style.css' rel='StyleSheet'/>";
		String includeScript = "<script type=\"text/javascript\" src='./js/lib.js'></script>" + "\n";
		return cssStyleSheet + includeScript + this.addJavascriptCode(iframe) + "\n" + fieldset;
	}
	
	private searchObject readSearchScriptConfig() throws MP2Exception {
		searchObject obj = new searchObject();
		BufferedReader br;
		char conjunction = '$';
		char order = '@';
		char filter = '%';
		String split = "=";
		try {
			br = new BufferedReader(new FileReader(ServletContext + ConfDirectory + SSMappingFile));
			String line;
			String currLine[] = null;
			while ((line = br.readLine()) != null) {
				if (line.trim().isEmpty() || (line.trim().charAt(0) == '#'))
					continue;
				currLine = line.split(split, 2);
				if (currLine.length == 2) {
					if (line.trim().charAt(0) == order) {
						String sort[] = currLine[1].split(split);
						obj.addSorts(currLine[0].substring(1), sort[0], (sort.length < 2) ? "" : sort[1]);
					}
					else if (line.trim().charAt(0) == conjunction)
						obj.addRelations(currLine[0].substring(1), currLine[1]);
					else if (line.trim().charAt(0) == filter)
						obj.addFilters(currLine[0].substring(1), currLine[1]);
					else
						obj.addResourceTypes(currLine[0], currLine[1]);
				}
			}
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			throw mp2;
		}
		return obj;
	}
	
	private void setSearchFieldSet(searchObject sobj, String list) {
		String lists[] = list.split(",");
		for (int i = 0; i < lists.length; i++) {
			if (sobj.getFilterViaLabel(lists[i]) != null)
				sobj.addSearchLists(lists[i], sobj.getFilterViaLabel(lists[i]));	
		}
	}
	
	private String getResults(HttpServletRequest req, searchObject so, String command) throws MP2Exception {
		SearchScriptMetaData md = new SearchScriptMetaData();
		resultObject ro			= new resultObject();
		this.setupMetaData(md);
		md.setResultsDelimiter(ro.getResultsDelimiter());
		if (this.getTotalRecords(so, md, ro))
			return "";
		//md.cleanCached();
		this.setupExtraFields(md);
		this.getWholeRecords(so, md, ro);
		md.clean();
		String result = this.presentResult(ro, so);
		md.cleanCached();
		return result;
	}
	
	private void setupExtraFields(SearchScriptMetaData md) throws MP2Exception {
		md.addField("type");
	}
	
	private String presentResult(resultObject ro, searchObject so) throws MP2Exception {
		String html = "";
		String suffix = ".";
		
		String titleStart = "[" + Delimiter + "]";
		String titleStop  = "[/" + Delimiter + "]";
		
		//produce sort dropdown list
		html += "<div align='right' name='"+repositorySortDiv+"' class='"+repositorySortDiv+"'>" + "\n";
		html += "<select onchange='javascript:repository_sortResult(this);' id='" + SortDropDown + "' name='" + SortDropDown + "'>" + "\n";
		html += "<option value=''>Sort by....</option>" + "\n";
		
		Iterator<String[]> pointer = so.getSorts().iterator(); 
		
		while (pointer.hasNext()) {
			String[] item = pointer.next();
			if (so.getSort().equals(item[1]))
				html += "<option value='" + item[1] + "' selected>" + item[0] + "</option>" + "\n";
			else 
				html += "<option value='" + item[1] + "' >" + item[0] + "</option>" + "\n";
		}
		
		html += "</select>" + "\n";
		html += "</div>" + "\n";
		html += "<br/>";
		html += "<div name='"+ repositoryTableDiv +"' class='"+ repositoryTableDiv +"'>" + "\n";
		html += "<table width='100%'>" + "\n";
		html += "<thead>" + "\n";
		html += "<th width='10%'><a href='#" + PageTop + "' onclick='javascript:checkedAll();'> " + SelectAllLabel +  " </a><br/><a href='#" + PageTop + "' onclick='javascript:unCheckedAll();'> " + UnSelectAllLabel + " </a></th>" + "\n";
		html += "<th width='70%'>Citation</th>" + "\n";
		html += "<th width='20%'>Resource Type</th>" + "\n";
		html += "</thead>" + "\n";
		
		String[] citations = this.getCitationsFromFile(ro.getFileToOpen());
		String[] records   = ro.getResults();
		if (citations == null) {
			return "";
		}
		for (int i = 0; i < citations.length; i++) {
			String current = citations[i];
			
			html += "<tr>" + "\n";
			String item[] = records[i].split(ro.getResultsDelimiter());
			html += "<td valign='top' align='left'>" + "\n";
			html += "<input type='checkbox' name='" + CitationCheckBox + "' id='"+ item[0] +"'/>";
			html += "</td>" + "\n";
			html += "<td>"  + "\n";
			
			current = current.replace(titleStart, "<a target='"+RepositoryURLTarget+"' href='" + RepositoryURL + item[0] + "'>");
			current = current.replace(titleStop, "</a>");
			
			html += current  + "\n";
			
			//html += "<a target='_blank' href='" + repositoryURL + item[0] + "'>";
			//html += citations[i];
			//html += "</a>"  + "\n";
			html += "</td>" + "\n";
			html += "<td valign='top' align='left'>" + "\n";
			item[1] = (item[1].trim().endsWith(suffix)) ? item[1].substring(0, item[1].length() - suffix.length()) : item[1];
			html += this.capitalizedFstLetter(item[1]);
			html += "</td>" + "\n";
			html += "</tr>" + "\n";
		}
		html += "</table>";
		html += this.printPageNumbers(ro, so);
		html += this.citationBox();
		html += "</div>" + "\n";
		
		ro = null;
		so = null;
		return this.addQuotation(html);
	}
	
	private String capitalizedFstLetter(String input) {
		input = input.trim();
		String inputs[] = input.split(" ");
		String result = "";
		for (int i = 0; i < inputs.length; i++) {
			result += Character.toUpperCase((inputs[i].charAt(0))) + inputs[i].substring(1) + " ";
		}
		return result;
	}

	private String printPageNumbers(resultObject ro, searchObject so) {
		String pagehtml  = "<div align='right' name='"+repositoryPageDiv+"' class='"+repositoryPageDiv+"'>";
		int totalResult = Integer.parseInt(ro.getTotalResult());
		int currentPage = so.getPageNumber();
		int pageLimit 	= 5;
		int allPages    = (totalResult % so.getItemPerPage() == 0) ?  (int) (totalResult / so.getItemPerPage()) : 
																	  (int) (totalResult / so.getItemPerPage()) + 1;
		if (totalResult > so.getItemPerPage()) {			
			if (currentPage != 1)
				pagehtml += "<a href='#" + PageTop + "' onclick='javascript:repository_getPage("+ (currentPage - 1) +");'> " +
							"<< Previous" +
							" </a>";
			int difference = currentPage + pageLimit - allPages - 1;
			if (difference > 0) {
				for (int i = difference; i > 0; i--) {
					if (currentPage > i)
						pagehtml += "<a href='#" + PageTop + "' onclick='javascript:repository_getPage("+ (currentPage - i) +");'> " +
									(currentPage - i) + " </a>";
				}
			}
			pagehtml += "<strong> " + currentPage +	" </strong>";
			difference = (difference > 0) ? difference : 0;
			for (int i = 1; (i < pageLimit - difference) && (allPages >= (currentPage + i)) ;i++) {
				pagehtml += "<a href='#" + PageTop + "' onclick='javascript:repository_getPage("+ (currentPage + i) +");'> " +
						(currentPage + i) +
						" </a>";
		
			}
			
			if (allPages > currentPage)
				pagehtml += "<a href='#" + PageTop + "' onclick='javascript:repository_getPage("+ (currentPage + 1) +");'> " +
							"Next >>" +
							" </a>";
		}
		pagehtml += " Total " +ro.getTotalResult()+ " Records.";
		pagehtml += "</div>";
		
		return pagehtml;
	}
	
	private String[] getCitationsFromFile(String file) throws MP2Exception {
		BufferedReader br;
		if (file == null) {
			return null;
		}
		try {
			br = new BufferedReader(new FileReader(file));
		} catch (FileNotFoundException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.OutPutFileNotFoundErr);
			e.printStackTrace();
			throw mp2;
		}
		if ((new File(file)).length() == 0)
			return null;
		
		String line;
		String output = "";
		try {
			while ((line = br.readLine()) != null) {
				output += line;
			}
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.ReadingOutPutFileErr);
			e.printStackTrace();
			throw mp2;
		}
		
		return output.split(TokenEnd);
	}
	
	private boolean getTotalRecords(searchObject so, SearchScriptMetaData md, resultObject ro) throws MP2Exception {
		this.setupFilters(so, md);
		String total = md.getTotalRecords();
		ro.setTotalResult(total);
		return (Integer.parseInt(total) == 0);
	}
	
	private void getWholeRecords(searchObject so, SearchScriptMetaData md, resultObject ro) throws MP2Exception {
		this.setupFilters(so, md);
		if (!so.getSort().equals("")) {
			md.setSorting(so.getSort(), so.getOrder());
			md.setupOrder();
		}
		md.setLimit(so.getPageNumber(), so.getItemPerPage());		
		ro.setFileToOpen(md.produce());
		ro.setResults(md.getMultiResults());
	}
	
	private void setupFilters(searchObject so, SearchScriptMetaData md) throws MP2Exception {
		md.setMultiFilters(so.getFilter(), so.getRelation());
		md.setPublicationTypes(so.getResourceType());
	}
	
	private void setSortArguments(HttpServletRequest req, searchObject so) {
		String sort = "sort";
		so.setSort(req.getParameter(sort));
		so.setPageNumber(1);
		this.setupTheRest(so, req);
	}
	
	private void setSearchArguments(HttpServletRequest req, searchObject so) {
		so.setPageNumber(1);
		this.setupTheRest(so, req);
	}
	
	private void setGetPageArguments(HttpServletRequest req, searchObject so) {
		String pageNumber = "page";
		String sort = "sort";
		so.setPageNumber(Integer.parseInt(req.getParameter(pageNumber)));
		so.setSort(req.getParameter(sort));
		this.setupTheRest(so, req);
	}
	
	private void setupTheRest(searchObject so, HttpServletRequest req) {
//		System.out.println("Setup the rest!!!!!!!!");
//		so.printSearchObject();
		this.addFilterPairs(so, req);
		this.addConjunctionPairs(so, req);
		this.setResourceType(so, req);
		this.setTemplate(so);
//		so.printSearchObject();
	}
	
	private void setTemplate(searchObject so) {
		if (so.getTemplate() == null || so.getTemplate().trim().length() == 0)
			return;
		String template = so.getTemplate().toLowerCase();
		so.addFilter(so.getTemplateName(), template.replace(" and ", " & "));
	}
	
	private void setResourceType(searchObject so, HttpServletRequest req) {
		so.setResourceType(req.getParameter(ResourceType));
	}
	
	private void addConjunctionPairs(searchObject so, HttpServletRequest req) {
		for (int i = 1; i < so.getSearchLists().size(); i++) {
			String output = this.getConjunction(i, req);
			so.setRelation(i+"", output);
		}
	}
	
	private String getConjunction(int index, HttpServletRequest req) {
		return req.getParameter(Conjunction + "_" + index);
	}
	
	private void addFilterPairs(searchObject so, HttpServletRequest req) {
		for (int i = 0; i < so.getSearchLists().size(); i++) {
			String output[] = this.getFilterPair(i, req);
			so.addFilter(output[0], output[1].trim());
		}
	}
	
	private String[] getFilterPair(int index, HttpServletRequest req) {
		String output[] = { req.getParameter(Fields + "_" + index), 
							req.getParameter(Query + "_" + index) };
		return output;
	}
	
	private String addJavascriptCode(String iframeUrl) {
		String script = "<script type=\"text/javascript\">" + "\n";
		//Global Variables
		script += "var ajaxObj;" +  "\n" +
				  "var chkhash=new Object();"  +  "\n" +
				  "var adjust=50;" +  "\n" +
				  "var browser;" +  "\n";
		// -> reset
		script += "function getBrowser() {" +  "\n" +
				  "var userAgent = window.navigator.userAgent.toLowerCase();" +  "\n" +
				  "if (userAgent.indexOf('msie 6') != -1)" +  "\n" +
				  "   browser='ie';" +  "\n" +
				  "else if (userAgent.indexOf('msie 7') != -1)" +  "\n" +
				  "   browser='ie';"+  "\n" +
				  "else if (userAgent.indexOf('opera') != -1)"  +  "\n" +
				  "   browser='opera';"  +  "\n" +
				  "else if (userAgent.indexOf('firefox') != -1)" +  "\n" +
				  "   browser='firefox';" +  "\n" +
			      "else if (userAgent.indexOf('safari') != -1)" +  "\n" +
				  "   browser='safari';" +  "\n" +
			      "else " +  "\n" +	
			      "browser='mozilla';" +  "\n" +
				  "}"  +  "\n" +
				  "function resize() {"	+ "\n" +
				  " var iframe=document.getElementById('" + repositoryInnerIframe + "');" + "\n" +
				  " var div=document.getElementById('" + SearchScriptDiv + "');" + "\n" +
				  " var height=div.scrollHeight+adjust;" + "\n" +
				  " var width=div.scrollWidth+adjust;" + "\n" +
				  //" if (browser=='ie' || browser=='safari'){" + "\n" +
				  //"  height=document.body.scrollHeight;" + "\n" +
				  //"  width =document.body.scrollWidth;" + "\n" +
				  //" } else {" + "\n" +
				  //"  height=document.body.offsetHeight+adjust;" + "\n" +
				  //"  width =document.body.offsetHeight+adjust;" + "\n" +
				  //" }" + "\n" +
				  "  var original_url='" + iframeUrl + "';" + "\n" +
				  "  iframe.src = original_url+'?height='+height+'&width='+width;" + "\n" +			
				  "}" + "\n" +
				  "function resetObj(name,sel) {" + "\n" +
				  "  var x;" + "\n" +
				  "  if (document.getElementsByName(name)) {" + "\n" +
				  "		x=document.getElementsByName(name);" + "\n" +
				  "		for (var i=0;i<x.length;i++) {" + "\n" +
				  "			if (sel) {" + "\n" +
				  "			x[i].selected=0;" + "\n" +
				  "			} else {" + "\n" +
				  "			x[i].value='';" + "\n" +
				  "	  		}}}" + "\n" +
				  "}" + "\n" +
				  "function repository_reset() {" + "\n" +
				  "  hideObj('"+ LoadingImageDiv +"', true);" + "\n" +
				  "	 if (ajaxObj)" + "\n" +
				  "  	ajaxObj.reset();" + "\n" +
				  "  resetObj('" + Conjunction + "', 'sel');" + "\n" +
				  "  resetObj('" + Fields + "', 'sel');" + "\n" +
				  "  resetObj('" + Query + "');" + "\n" +
				  "  resetObj('" + ResourceType + "');" + "\n" +
				  "  resetList();" + "\n" +
				  "	 hideObj('"+ DataTableDiv +"', true);" + "\n" +
				  "  resize();" + "\n" +
				  "}" + "\n" ;
		// -> checkbox 
		script += "function updateChecked() {" + "\n" +
		  		  "  var x=document.getElementsByName('" + CitationCheckBox + "');" + "\n" +
		  		  "  for (var i=0;i<x.length;i++) {" + "\n" +
		  		  "	   if (x[i].checked)" + "\n" +
		  		  "		  addToList(x[i].id);" + "\n" +
		  		  "	   else" + "\n" +
		  		  "		  rmFromList(x[i].id);"  + "\n" +
				  "  }	" + "\n" +
				  "}" + "\n" +
				  "function unCheckedAll() {" + "\n" +
		  		  "  var x=document.getElementsByName('" + CitationCheckBox + "');" + "\n" +
		  		  "  var value = '';" + "\n" +
		  		  "  var delimiter = ' - ';" + "\n" +
		  		  "  for (var i=0;i<x.length;i++) {" + "\n" +
		  		  "	 	x[i].checked=false;" + "\n" +
		  		  "	 }" + "\n" +
		  		  "}" + "\n" +
				  "function unChecked() {" + "\n" +
		  		  "	 unCheckedAll();" + "\n" +
		  		  "	 resetList();" + "\n" +
		  		  "}" + "\n" +
		  		  "function checkedAll() {" + "\n" +
		  		  "  var x=document.getElementsByName('" + CitationCheckBox + "');" + "\n" +
		  		  "  for (var i=0;i<x.length;i++) {" + "\n" +
		  		  "	 	x[i].checked=true;" + "\n" +
		  		"	 	addToList(x[i].id);" + "\n" +
		  		  "	 }" + "\n" +
		  		  "}" + "\n" +
		  		  "function getChecked() {" + "\n" +
		  		  "  var x=document.getElementsByName('" + CitationCheckBox + "');" + "\n" +
		  		  "  for (var i=0;i<x.length;i++) {" + "\n" +
		  		  "		   if (inList(x[i].id))" + "\n" +
		  		  "		   	   x[i].checked=true;" + "\n" +
		  		  "		   else" + "\n" + 
		  		  "			   x[i].checked=false;" + "\n" +
		  		  "	   }" + "\n" +
		  		  "}" + "\n" +
		  		  "function inList(pid) {" +
		  		  "  return (chkhash[pid]!=null);" + "\n" +
		  		  "}" + "\n" +
		  		  "function addToList(pid) {" + "\n" +
		  		  "  chkhash[pid]=pid;" + "\n" +
		  		  "}" + "\n" +
		  		  "function rmFromList(pid) {" + "\n" +
		  		  "  delete chkhash[pid];" + "\n" +
		  		  "}" + "\n" +
		  		  "function resetList() {" + "\n" +
		  		  "	 chkhash = new Object();" + "\n" +
		  		  "}" + "\n" +
		  		  "function checkSaved() {" + "\n" +
		  		  "  updateChecked();" + "\n" +
		  		  "  var value='';" + "\n" +
		  		  "  for (var key in chkhash) {" + "\n" +
		  		  "	 	value+=key;" + "\n" +
		  		  "	 }" + "\n" +
		  		  "  if (value=='')" + "\n" +
		  		  "		return false; " + "\n" +
		  		  "	 return true;" + "\n" +
		  		  "}" + "\n" +
		  		  "function repository_submitCitation() {" + "\n" +
		  		  "  updateChecked();" + "\n" +
		  		  "  var value='';" + "\n" +
		  		  "  var delimiter=', ';" + "\n" +
		  		  "  for (var key in chkhash) {" + "\n" +
		  		  "	 	value+=key+delimiter;" + "\n" +
		  		  "	 }" + "\n" +
		  		  "  if (value!='')" + "\n" +
		  		  "	 	value=value.substring(0, value.length-delimiter.length);" + "\n" +
		  		  "  document.getElementById('"+ repositoryPid + "').value='['+value+']';" + "\n" +
		  		  "}" + "\n";
		// -> search, getpage, sort
		script += "function setValuesByName(name) {" + "\n" +
				  "	var x;" + "\n" +
				  "	if (document.getElementsByName(name)) {" + "\n" +
				  "		x=document.getElementsByName(name);" + "\n" +
				  "		for (var i=0;i<x.length;i++) {" + "\n" +
				  "			if (!ajaxObj.failed) {" + "\n" +
				  "				ajaxObj.setVar(x[i].id, x[i].value);" + "\n" +
				  "			}" + "\n" +
				  "		}" + "\n" +
				  "	}" + "\n" +
				  "}" + "\n" +
				  "function hideObj(objId, hide) {" + "\n" +
				  "	if (document.getElementById(objId)) {" + "\n" +
				  "		var obj=document.getElementById(objId);" + "\n" +
				  "		if (!hide) {" +
				  "			obj.style.display='block';" + "\n" +
				  "			obj.style.visibility='visible';" + "\n" +
				  "		} else {" +
				  "			obj.style.display='none';" + "\n" +
				  "			obj.style.visibility='hidden';" + "\n" +
				  "		}" + "\n" +
				  "	}" + "\n" +
				  "	resize();" + "\n" +
				  "}" + "\n" +
				  "function setDivText(text) {" + "\n" +
				  "	hideObj('"+ LoadingImageDiv +"', true);" + "\n" +
				  "	if (document.getElementById('" + DataTableDiv + "')) {" + "\n" +
				  "		var obj=document.getElementById('" + DataTableDiv + "');" + "\n" +
				  "		if (text.length>0)" + "\n" +
				  "			obj.innerHTML=text;" + "\n" +
				  "		else" + "\n" +
				  "			obj.innerHTML='<b>" + NoResultReturns + "</b>';" + "\n" +
				  "		hideObj('"+ DataTableDiv +"',false);" + "\n" +
				  "	}" + "\n" +
				  "}" + "\n" +
				  "function repository_search() {" + "\n" +
				  "	hideObj('"+ DataTableDiv +"', true);" + "\n" +
				  "	hideObj('"+ LoadingImageDiv +"', false);" + "\n" +
				  "	ajaxObj=new AjaxUtil('" + RequestURL + "', this);" + "\n" + 
				  "	if (ajaxObj.failed) {" + 
				  "		return;" +
				  "	}" + "\n" +
				  "	ajaxObj.processURLString('', false);" + "\n" +
				  "	setValuesByName('" + repositoryTemplate + "');" + "\n" +
				  "	setValuesByName('" + Conjunction + "');" + "\n" +
				  "	setValuesByName('" + Fields + "');" + "\n" +
				  "	setValuesByName('" + Query + "');" + "\n" +
				  "	setValuesByName('" + ResourceType + "');" + "\n" +
				  "	ajaxObj.setVar('command', 'search');" + "\n" +
				  "	ajaxObj.onCompletion =  function() {" + "\n" +
				  "		this.obj.setDivText(this.xmlhttp.responseText);" + "\n" +
				  "	}" + "\n" +
				  "	ajaxObj.runAJAX();" + "\n" +
				  " resetList();" + "\n" +
				  "}" + "\n" +
				  "function repository_sortResult(obj) {" + "\n" +
				  "	hideObj('"+ DataTableDiv +"', true);" + "\n" +
				  "	hideObj('"+ LoadingImageDiv +"', false);" + "\n" +				  
				  "	ajaxObj=new AjaxUtil('" + RequestURL + "', this);" + "\n" + 
				  "	if (ajaxObj.failed) {" + 
				  "		return;" +
				  "	}" + "\n" +
				  "	ajaxObj.processURLString('', false);" + "\n" +
				  "	setValuesByName('" + repositoryTemplate + "');" + "\n" +
				  "	setValuesByName('" + Conjunction + "');" + "\n" +
				  "	setValuesByName('" + Fields + "');" + "\n" +
				  "	setValuesByName('" + Query + "');" + "\n" +
				  "	setValuesByName('" + ResourceType + "');" + "\n" +
				  "	ajaxObj.setVar('command', 'sort');" + "\n" +
				  "	ajaxObj.setVar('sort', obj.value);" + "\n" +
				  "	ajaxObj.onCompletion =  function() {" + "\n" +
				  "		this.obj.setDivText(this.xmlhttp.responseText);" + "\n" +
				  "	}" + "\n" +
				  "	ajaxObj.runAJAX();" + "\n" +
				  " resetList();" + "\n" + 
				  "}"  + "\n" +
				  "function repository_getPage(page) {" + "\n" +
				  " updateChecked();" + "\n" +
				  "	hideObj('"+ DataTableDiv +"', true);" + "\n" +
				  "	hideObj('"+ LoadingImageDiv +"', false);" + "\n" +
				  "	ajaxObj=new AjaxUtil('" + RequestURL + "', this);" + "\n" + 
				  "	if (ajaxObj.failed) {" + 
				  "		return;" +
				  "	}" + "\n" +
				  "	ajaxObj.processURLString('', false);" + "\n" +
				  "	setValuesByName('" + repositoryTemplate + "');" + "\n" +
				  "	setValuesByName('" + Conjunction + "');" + "\n" +
				  "	setValuesByName('" + Fields + "');" + "\n" +
				  "	setValuesByName('" + Query + "');" + "\n" +
				  "	setValuesByName('" + ResourceType + "');" + "\n" +
				  "	ajaxObj.setVar('command', 'getpage');" + "\n" +
				  "	ajaxObj.setVar('sort', document.getElementById('"+ SortDropDown +"').value);" + "\n" +
				  "	ajaxObj.setVar('page', page);" + "\n" +
				  "	ajaxObj.onCompletion =  function() {" + "\n" +
				  "		this.obj.setDivText(this.xmlhttp.responseText);" + "\n" +
				  "		this.obj.getChecked();" + "\n" +
				  "	}" + "\n" +
				  "	ajaxObj.runAJAX();" + "\n" +
				  "}";// + "\n" +
				  //"getBrowser();";
		script += "</script>";
		return script;	
	}
	
	private String citationBox() {
		String fieldset = "<form action='" +CitationRequest+ "' method='post' onSubmit='return checkSaved()'>" + "\n" +
						  "<div id='"+ SaveCitationDiv +"' class='"+ SaveCitationDiv +"'>" +
						  "<fieldset><legend>Save Citation</legend>" + "\n" + 
							"<dl><dt>Citation Format</dt>" + "\n" +
							"<dd>" + "\n" +
							"<select name='format' id='" + CitationDropDown + "'>" + "\n" +
								"<option value='Text'>Plain Text Citation</option>" + "\n" +	
								"<option value='HTML'>HTML Citation</option>" + "\n" +
								"<option value='EndNote'>EndNote Citation</option>" + "\n" +
							"</select></dd>" + "\n" +
							"<dd>" + "\n" +
							"<input style='width:90%;' type='text' name='" + Address + "' id='" + Address + "'/>" + "\n" +
							"</dd>" + "\n" +
							"<dt></dt>" + "\n" +
							"<dd>" + "\n" +
							
							this.produceButton("submit", "Send Citation", "repository_submitCitation()", "button", "repository_send", "") + "\n" + 
							" OR " + "\n" +
							this.produceButton("submit", "Save Citation", "repository_submitCitation()", "button", "repository_save", "") + "\n" +
							"<BR/>"+ "\n" +
							this.produceButton("button", "Clear All Citations", "unChecked()", "button", "repository_clear_citations", "") + "\n" +
							"<input type='hidden' name='pid' id='"+ repositoryPid +"'/>" + "\n" +
							"</dd>" + "\n" +
						    "</dl>" + "\n" + 
						  "</fieldset>"  + "\n" +
						  "</div>" +
						  "</form>";						  
		return fieldset;
	}
	
	private String getSearchFieldSet(searchObject so, String iframe) {
		String searchFieldSet = "";
		try {
			searchFieldSet += this.printSearchFrame(so, iframe);	//print search fieldset.
		} catch (MP2Exception e) {
			e.setMessage("Getting Error When Printing out Search Frame");
			e.printStackTrace();
		}
		return searchFieldSet;
	}
	
	private void setupMetaData(SearchScriptMetaData md) throws MP2Exception {
		md.setWebRoot(ServletContext);
		md.setXSLFile(ServletContext + XSLDirectory + Stylesheet);
		md.setConfFile(ServletContext + ConfDirectory + ConfFile);
		md.setMappingFile(ServletContext + ConfDirectory + DBMappingFile);
		md.setTempDirectory(ServletContext + TempDirectory);
		md.setTempFileSuffix(TempFileSuffix);
		md.setMetaData(this.MetaData);
		md.setFedora(this.Fedora);
		md.addHeader(TokenHeader);
		md.addFeet(TokenEnd);
		md.setupSearchModel();
		md.setupMetaDataModel();
	}
	
	//check session
	// if new session
	// 		create the variables that needs to store in the session and set session time-out
	// else
	//		check command and start loading stuff
	protected void requestHandler(HttpServletRequest request, HttpServletResponse response) {
		response.setContentType("text/html");
		response.setCharacterEncoding("UTF-8");
		String command 			= request.getParameter(Command);
		String iFrameUrl		= request.getParameter(IFrameURL);
		ServletContext 			= getServletContext().getRealPath("") + FS;
		String results 			= "";
		searchObject so 		= new searchObject();
		System.out.println("Stage0");
		try {
			this.readFromConfig();
		} catch (MP2Exception e) {
			this.printException(e.getMessage());
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.ReadingConfFileErr);			
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
		}
		System.out.println("Stage1");
		try {
			so = this.readSearchScriptConfig();			
		} catch (MP2Exception e) {
			e.setMessage("Getting Error When Reading Configuration File for Search Framework");
			e.printStackTrace();
		}
		System.out.println("Stage2");
		so.setTemplateName(Template);
		if (request.getParameter(Template) != null)
			so.setTemplate(request.getParameter(Template));
		else
			so.setTemplate(request.getParameter(repositoryTemplate));
		
		this.setSearchFieldSet(so, this.SearchFieldSet);
		System.out.println("Stage3");
		
		if ((command == null) || (command.trim().length() == 0)) {
			results = this.getSearchFieldSet(so, iFrameUrl);
		} else if (command.equalsIgnoreCase("sort"))
			this.setSortArguments(request, so);
		else if (command.equalsIgnoreCase("search"))
			this.setSearchArguments(request, so);
		else if (command.equalsIgnoreCase("getpage"))
			this.setGetPageArguments(request, so);
		
		System.out.println("Stage4");
		try {
			if (results.equals(""))
				results = this.getResults(request, so, command);
		} catch (MP2Exception e) {
			this.printException(e.getMessage());
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage("Getting Error When Getting the Results");			
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
		}
		System.out.println("Stage5");
		try {
			PrintWriter out = response.getWriter();
			out.print(results);
		} catch (IOException e) {
			this.printException(e.getMessage());
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage("Getting Error When Printing the Results");			
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
		}
		System.out.println("Stage6");
		this.clean();
	}
	
	private String printException(String msg) {
		String labelLeft = "<h3>";
		String errorMsg	 = " Error found: ";
		String labelRight = "</h3>";
		return DWLeftBracket + labelLeft + errorMsg + labelRight + msg + DWRightBracket + printNewLine();
	}

	private String printNewLine() {
		return DWLeftBracket + "<br>" + DWRightBracket;
	}
}
